package io.github.luons.mediator.dsl.aspect;

import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import io.github.luons.mediator.core.constant.Constant;
import io.github.luons.mediator.core.spi.PageBean;
import io.github.luons.mediator.core.spi.result.BaseResult;
import io.github.luons.mediator.dsl.handler.RequestHolder;
import io.github.luons.mediator.dsl.utils.MediatorUtils;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.context.annotation.DependsOn;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import java.util.List;
import java.util.Map;
import java.util.Objects;

/**
 * pageAspect
 *
 * @author : luons
 */
@Slf4j
@Aspect
@Component
@Order(2)
public class  PageableAspect {

    /**
     * page threadLocal
     */
    private static final ThreadLocal<PageBean<Object>> PAGE_BEAN_THREAD_LOCAL = ThreadLocal.withInitial(PageBean::new);

    @Around(value = "@annotation(io.github.luons.mediator.dsl.aspect.Pageable)")
    public Object pageableAspect(ProceedingJoinPoint point) throws Throwable {

        Object pageNumberObj;
        Object pageSizeObj;
        if (MediatorUtils.PAGE_THREAD_LOCAL.get() != null) {
            pageNumberObj = MediatorUtils.PAGE_THREAD_LOCAL.get().getPageNum();
            pageSizeObj = MediatorUtils.PAGE_THREAD_LOCAL.get().getPageSize();
        } else {
            pageNumberObj = MediatorUtils.getRequestValueByKey(Constant.PAGE_NUMBER);
            pageSizeObj = MediatorUtils.getRequestValueByKey(Constant.PAGE_SIZE);
        }
        if (Objects.isNull(pageNumberObj) || Objects.isNull(pageSizeObj)) {
            return point.proceed();
        }
        int pageNumber = Integer.parseInt(pageNumberObj.toString());
        if (pageNumber == -1) {
            return point.proceed();
        }
        int pageSize = Integer.parseInt(pageSizeObj.toString());
        if (pageSize <= 0) {
            throw new Exception("pageSize is not illegal");
        }
        pageSize = Math.min(pageSize, MediatorUtils.MAX_PAGE_SIZE);
        MediatorUtils.PAGE_THREAD_LOCAL.set(PageHelper.startPage(pageNumber, pageSize));
        return point.proceed();
    }

    @SuppressWarnings("unchecked")
    @Around(value = "@annotation(io.github.luons.mediator.dsl.aspect.Pageable)")
    public Object pageableParam(ProceedingJoinPoint point) throws Throwable {
        Object value = point.proceed();
        Page<Object> page = MediatorUtils.PAGE_THREAD_LOCAL.get();
        PageBean<Object> pageBean = PAGE_BEAN_THREAD_LOCAL.get();
        if (!(value instanceof BaseResult)) {
            return value;
        }
        BaseResult<Object> result = (BaseResult<Object>) value;
        Object resultData = result.getResult();
        if (!(resultData instanceof PageBean)) {
            if (resultData instanceof Map && page != null && page.size() > 0) {
                ((Map<String, Object>) resultData).put("totalCount", page.getTotal());
            }
            return value;
        }
        PageBean<Object> rdpBean = ((PageBean<Object>) resultData);
        List<Object> dataList = rdpBean.getData();
        pageBean.setData(dataList);
        if (!CollectionUtils.isEmpty(page)) {
            if (pageBean.getPageNumber() == null) {
                pageBean.setPageNumber(page.getPageNum());
                pageBean.setPageSize(page.getPageSize());
            }
            pageBean.setTotalCount(Long.valueOf(page.getTotal()).intValue());
        }
        if (pageBean.getPageNumber() == null) {
            pageBean.setPageNumber(1);
            pageBean.setPageSize(10);
            pageBean.setTotalCount(rdpBean.getTotalCount() != null ? rdpBean.getTotalCount() : dataList.size());
        }
        result.setResult(pageBean);
        MediatorUtils.PAGE_THREAD_LOCAL.remove();
        PAGE_BEAN_THREAD_LOCAL.remove();
        return result;
    }

}
